Many programming languages provide a mechanism for indicating that a subroutine can accept a varying number of arguments at run time. For example, the C and C++ languages provide a mechanism commonly known as "varargs". Hereafter, the term "varargs" subroutine will be used to refer to a subroutine in any source language with this property. The C subroutine "printargs", shown below is an example of such a subroutine:
______________________________________ void printargs(int arg.sub.-- cnt, . . . ) int i; va.sub.-- list pvar; va.sub.-- start (pvar, arg.sub.-- cnt); for (i = 0; i &lt; arg.sub.-- cnt; i++) { printf("arg[%d] = %d.backslash.n", i, va.sub.-- arg(pvar, int)); } va.sub.-- end(pvar); } ______________________________________
For those not familiar with the C language, the possible sequences of statements in the above subroutine is illustrated in FIG. 1. The subroutine "printargs" as shown therein, may be called at call sites which pass different numbers of integer-valued arguments to the subroutine (as in the sample calls shown below). A call site syntax provides the name of the called subroutine, followed by a first argument which defines the number of arguments to be passed by the call, followed by the argument(s) themselves:
______________________________________ CALL SITE EFFECT WHEN CALLED ______________________________________ 1: printargs(0); (none) 2: printargs(1,142); arg[0] = 142 3: printargs(2,11,-22); arg[0] = 11 arg[1] = -22 4: printargs(1,99); arg[0] = 99 ______________________________________
A subroutine in C is described by a signature and a body. The signature is the first line of the subroutine, and describes the name of the subroutine, the return value of the subroutine, and the number, name, and type of each subroutine argument. For instance, the following signature EQU int abc(int a, char b, double c )
describes a routine named "abc" which requires exactly three arguments from each caller. The first argument "a" must be of integer type (i.e., "int"), the second argument "b" of character type (i.e., "char"), and the third argument "c" of double-precision floating-point type (i.e., "double"). Additionally, the subroutine abc returns a value of integer type to the caller.
Signatures, such as the one above that precisely specify the number and type of arguments the caller must pass, are called "fixedarg" signatures, and subroutines with such signatures are called "fixedarg subroutines". A fixedarg signature specifically identifies each argument that will be used by the fixedarg subroutine and enables the subroutine to refer to the argument by "name".
The signature is followed by a sequence of program statements which make up the body of the subroutine. The body encompasses all statements between an opening brace { and a closing brace }. The arguments named in the signature may be referred to (or accessed) in the body by using the argument name.
In the printargs subroutine (as shown in FIG. 1), the signature is: EQU void printargs(int arg.sub.-- cnt, . . . )
Such a signature indicates, by means of an ellipsis ". . . " in the argument description, that the subroutine will accept a varying number of arguments from its callers; that is, it is a varargs subroutine. It also names a single fixed argument of integer type which is required to be passed by all callers. In this case there is no name that refers to the other arguments. To determine the value of those arguments in the body of the subroutine, the programmer must employ special program statements. Those statements are "va.sub.-- start", "va.sub.-- arg", and "va.sub.-- end". "Va.sub.-- start" is an instruction to start with a first argument; "va.sub.-- arg" is an instruction to move to a next argument; and "va.sub.-- end" indicates that the subroutine is finished. Each appearance of one of these constructs in the subroutine body is termed a varargs access.
As shown in FIG. 1, the printargs subroutine commences at Block 1 with an integer count set to 0 and a test is made to determine if the count is less than the argument count indicated by the call. If yes, a next argument is accessed that has been passed from the call site and the procedure of the subroutine operates thereupon (Block 2). The integer count is incremented and if still less than the argument count, the procedure repeats with a next argument. Otherwise, the procedure ends (Block 3).
Calls to varargs subroutines often require more processing than calls to equivalent fixedarg subroutines, because the number of arguments is unknown (as is their type) and so may need to be moved from locations specified by the caller into locations expected by the callee. For instance, compilers for the Hewlett-Packard 700 and 800 series work stations use an extra instruction sequence known as an "argument relocation stub" that is interposed between caller and callee to move each varargs argument. The execution of these extra instructions makes a call to a varargs subroutine slower than a call to an equivalent fixedarg subroutine,
Varargs subroutines can limit the effectiveness of interprocedural optimizations. For example, it is impossible to directly insert a varargs subroutine inline in a code listing, because inlining requires that each argument reference in the callee be identified with a particular argument in the caller. Varargs subroutines also do not allow accurate per-parameter information to be collected during interprocedural analysis.
Accordingly, there is a need for a compile procedure which improves the execution time of a program that includes vararg subroutines. Further, such a compile method, in replacing vararg subroutines with fixedarg subroutines, should avoid untoward code growth.